import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class DateParser {
	private Date parsedDate;
	private Date dateNow;
	
	interface IPatternHandler {
		Date handleMatches(Matcher m);
	}
	
	class PatternChecker {
		Pattern pattern;
		IPatternHandler handler;
		
		PatternChecker(Pattern p, IPatternHandler h) {
			this.pattern = p;
			this.handler = h;
		}
	}

	List<PatternChecker> patternCheckers = new LinkedList<PatternChecker>();

	public DateParser() {
		this(new Date());
	}
	
	/**
	 * DateParser Constructor
	 * Set the day of reference for parsing as given date "now"
	 * 
	 * @param now
	 */
	public DateParser(final Date now) {
		this.dateNow = now;

		// [x] decade ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("([0-9]*)\\sdecade(s?)\\sago", Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						while (m.find()) {
							String s = m.group(1);
							int days = Integer.parseInt(s);
							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);								
							calendar.add(Calendar.YEAR, -(days*10));
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

		// [x] years ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("([0-9]*)\\syear(s?)\\sago", Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						while (m.find()) {
							String s = m.group(1);
							int days = Integer.parseInt(s);
							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);								
							calendar.add(Calendar.YEAR, -days);
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

		// [x] months ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("([0-9]*)\\smonth(s?)\\sago", Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						while (m.find()) {
							String s = m.group(1);
							int days = Integer.parseInt(s);
							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);								
							calendar.add(Calendar.MONTH, -days);
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

		// [x] days ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("([0-9]*)\\sday(s?)\\sago", Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						while (m.find()) {
							String s = m.group(1);
							int days = Integer.parseInt(s);
							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);								
							calendar.add(Calendar.DAY_OF_YEAR, -days);
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

		// hours ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("hour(s?) ago",Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						if (m.find()) {							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

		// mins ago
		patternCheckers.add(new PatternChecker(
				Pattern.compile("minute(s?) ago",Pattern.CASE_INSENSITIVE),
				new IPatternHandler() {
					public Date handleMatches(Matcher m) {
						if (m.find()) {							
							Calendar calendar = Calendar.getInstance();
							calendar.setTime(dateNow);
							
							return calendar.getTime();								
						}
						return null;
					}
				}));

	}
	

	public boolean parse(String d) {
		
		for (PatternChecker patternChecker : patternCheckers) {
			Matcher m = patternChecker.pattern.matcher(d);
			Date dateSBPair = patternChecker.handler.handleMatches(m);
			
			if (dateSBPair != null) {
				//System.out.println("success!");
				Calendar c = Calendar.getInstance();
				c.setTime(dateSBPair);
				c.set(Calendar.HOUR_OF_DAY, 23);
				c.set(Calendar.MINUTE, 59);
				c.set(Calendar.SECOND, 59);
				dateSBPair = c.getTime();

				setParsedDate(dateSBPair);
				return true;
			}
		}
		
		return false;
	}
	
	public Date getParsedDate() {
		return parsedDate;
	}
	
	public String getDateString() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(getParsedDate());
		
		String month = ""+(calendar.get(Calendar.MONTH)+1);
		if (month.length() == 1) month = "0" + month;
		
		String day = "" + calendar.get(Calendar.DAY_OF_MONTH);
		if (day.length() == 1) day = "0" + day;
		
		return calendar.get(Calendar.YEAR) + "-" +  month + "-" + day;
	}

	private void setParsedDate(Date parsedDate) {
		this.parsedDate = parsedDate;
	}
}
